//
// Created by antler on 2018/11/9.
//

// 图像命令
#include "lprefix.h"

#include "lua.hpp"
#include "luaext.hpp"

#include "log.h"
#include "GlobalMacros.h"

#include "Image.h"

int image_fromScreen(lua_State *L) {
    Image *ret = nullptr;

    int argc = lua_gettop(L);
    if (argc == 0) {
        ret = Image::fromScreen();
    } else if (argc == 1) {
        Rect *rect = (Rect *) toluahelper_tousertype(L, 1, USERTYPE_RECT, nullptr);
        if (rect) {
            ret = Image::fromScreen(*rect);
        }
    }

    if (ret) {
        LOGV("Image.fromScreen self:%p", ret);
        tolua_pushusertype_and_takeownership(L, ret, USERTYPE_IMAGE);
    } else {
        lua_pushnil(L);
    }
    return 1;
}

int image_fromFile(lua_State *L) {
    Image *ret = nullptr;

    int argc = lua_gettop(L);
    if (argc == 1) {
        const char *filePath = luaL_checkstring(L, 1);
        ret = Image::fromFile(filePath);
    }

    if (ret) {
        LOGV("Image.fromScreen self:%p", ret);
        tolua_pushusertype_and_takeownership(L, ret, USERTYPE_IMAGE);
    } else {
        lua_pushnil(L);
    }
    return 1;
}

int image_destructor(lua_State *L) {
    Image *self = (Image *) tolua_tousertype(L, 1, 0);
    LOGV("image:destructor self:%p", self);
    SAFE_DELETE(self);
    return 0;
}

int image_tostring(lua_State *L) {
    Image *self = (Image *) toluahelper_tousertype(L, 1, USERTYPE_IMAGE, nullptr);
    if (self) {
        lua_pushfstring(L, "%s<Bitmap:%p, Size[%d x %d], imageType:%s>", tolua_typename(L, 1),
                        self->getBitmapObject(),
                        self->getWidth(), self->getHeight(), self->getImageFromTypeName().c_str());
    } else {
        lua_pushfstring(L, "class: %p", lua_topointer(L, 1));
    }
    return 1;
}

int image_release(lua_State *L) {
    Image *self = (Image *) toluahelper_tousertype(L, 1, USERTYPE_IMAGE, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'release'", nullptr);
    }
    LOGV("image:release self:%p", self);
    self->release();
    return 0;
}

int image_getSize(lua_State *L) {
    Image *self = (Image *) toluahelper_tousertype(L, 1, USERTYPE_IMAGE, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getSize'", nullptr);
    }
    Size *size = Size::createWith(self->getSize());
    tolua_pushusertype_and_takeownership(L, size, USERTYPE_SIZE);
    return 1;
}

int image_getWidth(lua_State *L) {
    Image *self = (Image *) toluahelper_tousertype(L, 1, USERTYPE_IMAGE, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getWidth'", nullptr);
    }
    lua_pushinteger(L, self->getWidth());
    return 1;
}

int image_getHeight(lua_State *L) {
    Image *self = (Image *) toluahelper_tousertype(L, 1, USERTYPE_IMAGE, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getHeight'", nullptr);
    }
    lua_pushinteger(L, self->getHeight());
    return 1;
}

int image_setRotation(lua_State *L) {
    Image *self = (Image *) toluahelper_tousertype(L, 1, USERTYPE_IMAGE, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'setRotation'", nullptr);
    }

    int rotation = (luaL_checkinteger(L, 2));
    if (abs(rotation) == Image::ROTATION_CLOCKWISE_90 ||
        abs(rotation) == Image::ROTATION_CLOCKWISE_180 ||
        abs(rotation) == Image::ROTATION_CLOCKWISE_270) {
        self->setRotation(rotation * 90.f);
    } else {
        tolua_Error tolua_err = {1, 0, "Image.ROTATION_CLOSEWISE"};
        tolua_error(L, "#fimage:setRotation", &tolua_err);
    }

    return 0;
}

int image_saveToFile(lua_State *L) {
    Image *self = (Image *) toluahelper_tousertype(L, 1, USERTYPE_IMAGE, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'saveToFile'", nullptr);
    }

    const char *filePath = luaL_checkstring(L, 2);
    self->saveToFile(filePath);
    return 0;
}

int image_clip(lua_State *L) {
    Image *self = (Image *) toluahelper_tousertype(L, 1, USERTYPE_IMAGE, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'clip'", nullptr);
    }

    tolua_Error tolua_err;
    Rect *rect = (Rect *) toluahelper_tousertype(L, 2, USERTYPE_RECT, nullptr, &tolua_err);
    if (rect) {
        self->clip(*rect);
    } else {
        tolua_error(L, "#fimage:clip", &tolua_err);
    }
    return 0;
}

int image_getRGB(lua_State *L) {
    Image *self = (Image *) toluahelper_tousertype(L, 1, USERTYPE_IMAGE, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getRGB'", nullptr);
    }

    Color3B c3b;

    int argc = lua_gettop(L) - 1;
    if (argc == 1) {
        tolua_Error tolua_err;
        Point *point = (Point *) toluahelper_tousertype(L, 2, USERTYPE_POINT, nullptr, &tolua_err);
        if (point) {
            self->getColor(*point, c3b);
        } else {
            tolua_error(L, "#fimage:getRGB", &tolua_err);
        }
    } else if (argc == 2) {
        int x = luaL_checkint(L, 2);
        int y = luaL_checkint(L, 3);

        self->getColor(Point(x, y), c3b);
    }

    lua_pushinteger(L, c3b.r);
    lua_pushinteger(L, c3b.g);
    lua_pushinteger(L, c3b.b);
    return 3;
}

int image_getColor(lua_State *L) {
    Image *self = (Image *) toluahelper_tousertype(L, 1, USERTYPE_IMAGE, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'getColor'", nullptr);
    }

    Color3B c3b;

    int argc = lua_gettop(L) - 1;
    if (argc == 1) {
        tolua_Error tolua_err;
        Point *point = (Point *) toluahelper_tousertype(L, 2, USERTYPE_POINT, nullptr, &tolua_err);
        if (point) {
            self->getColor(*point, c3b);
        } else {
            tolua_error(L, "#fimage:getColor", &tolua_err);
        }
    } else if (argc == 2) {
        int x = luaL_checkint(L, 2);
        int y = luaL_checkint(L, 3);

        self->getColor(Point(x, y), c3b);
    }

    Color3B *ret = Color3B::createWith(c3b);
    tolua_pushusertype_and_takeownership(L, ret, USERTYPE_COLOR3B);
    return 1;
}

int image_binarize(lua_State *L) {
    Image *self = (Image *) toluahelper_tousertype(L, 1, USERTYPE_IMAGE, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'binarize'", nullptr);
    }

    return 0;
}

static const luaL_Reg funcs[] = {
        {"fromScreen",  image_fromScreen},
        {"fromFile",    image_fromFile},
        {"__tostring",  image_tostring},
        {"release",     image_release},
        {"getSize",     image_getSize},
        {"getWidth",    image_getWidth},
        {"getHeight",   image_getHeight},
        {"setRotation", image_setRotation},
        {"saveToFile",  image_saveToFile},
        {"clip",        image_clip},
        {"getRGB",      image_getRGB},
        {"getColor",    image_getColor},
        {"binarize",    image_binarize},
        {nullptr,       nullptr}
};

static int get_ROTATION_CLOCKWISE_90(lua_State *L) {
    lua_pushinteger(L, Image::ROTATION_CLOCKWISE_90);
    return 1;
}

static int get_ROTATION_CLOCKWISE_180(lua_State *L) {
    lua_pushinteger(L, Image::ROTATION_CLOCKWISE_180);
    return 1;
}

static int get_ROTATION_CLOCKWISE_270(lua_State *L) {
    lua_pushinteger(L, Image::ROTATION_CLOCKWISE_270);
    return 1;
}

LUAMOD_API int luaopen_image(lua_State *L) {
    tolua_open(L);

    tolua_module(L, nullptr, 0);
    tolua_beginmodule(L, nullptr);
    {
        tolua_usertype(L, USERTYPE_IMAGE);
        tolua_cclass(L, CLASSNAME_IMAGE, USERTYPE_IMAGE, "", image_destructor);

        tolua_beginmodule(L, CLASSNAME_IMAGE);
        {
            toluahelper_setfunc(L, funcs);

            TOLUAHELPER_CLASS_CONST_VARIABLE(L, ROTATION_CLOCKWISE_90);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, ROTATION_CLOCKWISE_180);
            TOLUAHELPER_CLASS_CONST_VARIABLE(L, ROTATION_CLOCKWISE_270);
        }
        tolua_endmodule(L);
    }
    tolua_endmodule(L);
    return 0;
}